#!/usr/local/bin/ruby
#
#  Copyright (c) 2009 Mu Dynamics, Inc. All rights reserved.

require 'rubygems'
require 'libxml'
require 'lib/api/rest/mu_api'
require 'ddt_api'
# require 'spawn/lib/spawn'  # uncomment to use spawn

include LibXML
# include Spawn   # uncomment to use spawn

class Run < ActiveRecord::Base
  validates_presence_of :mu_ip, :testbed_name, :testbed_uuid, :target_name, :target_uuid,
    :scenario_name, :scenario_uuid, :testsuite_name, :testsuite_uuid
  has_many :results

  $select_one = " Select One ..."

  # from $mu_ip, get testbeds, targets, scenarios, and test suite names and uuids
  # and store them in hashmaps
  def self.populate(mu_ip=ENV['MU_IP'])
    $mu_ip = mu_ip
    logger.debug "run.populate called with #{$mu_ip}"

    $testbeds = self.get_map("Testbed")
    $testbeds["#{$select_one}"] = ""

    $targets = self.get_map("Target")
    $targets["#{$select_one}"] = ""

    $scenarios = self.get_map("Scenario")
    $scenarios["#{$select_one}"] = ""
   
    $testsuites = self.get_map("DDTSuite")
    $testsuites["#{$select_one}"] = ""

  end

  def self.get_map(type="Scenario")
    # request the testbed template information from the Mu
    map = Hash.new
    # @api = Mu_Api.new($mu_ip, "/rai/rest/mu")
    api = DdtApi.new($mu_ip, "/rai/rest/mu")
    result = api.request("findUsing?type=#{type}")

    # get the uuids and names from the response
    uuids = []
    names = []
    result.find("//result").each do | t |
        uuids << t.attributes['uuid'] unless t.attributes['uuid'] == "" or t.attributes['uuid'].nil?
    end

    result.find("//name").each do | n |
      names << n.content unless n.content == "" or n.content.nil?
    end

    # map the names and uuids
    names.size.times do | idx |
      map[names[idx]] = uuids[idx]
    end

    return map
  end

  def self.mu_ip
    return $mu_ip
  end

  def self.scenarios
    return $scenarios
  end

  def self.targets
    return $targets
  end

  def self.testbeds
    return $testbeds
  end

  def self.testsuites
    return $testsuites
  end

  def self.clear_templates
    $targets = nil
    $testbeds = nil
    $scenarios = nil
    $testsuites = nil
  end

  # get the run parameters from the db and pass them along to the run_test method
  def execute(run_id)
     r = []
     rows = ActiveRecord::Base.connection.execute("select * from runs where id='#{run_id}'")
     rows.each_hash{ |res| r << res }
     r.each do | rr |
       run_test(rr)
     end
   end

   # non-blocking call that spawns a thread to execute the test suite and post the results to the db
   #  for a simpler blocking implementation,
   #     just remove the 'spawn do' line, its corresponding 'end', and the spawn require at the top of this file
   def run_test(run)
   #  spawn(:method => :thread) do  # uncomment to use spawn
      @run_id = run['id']
      $DEBUG and logger.debug "starting test run #{@run_id}"

      # set up the session and network configuration
      if $mu_ip.nil?
        $mu_ip = ENV['MU_IP']
      end

      # initializes a new DdtApi object and set up the session and network configuration
      @api = DdtApi.new($mu_ip)
      @api.new_session
      @api.testbed(run['testbed_uuid'])
      @api.target(run['target_uuid'])
      @api.setup_session
      #sleep 4 # wait for testbed setup

      # set up the scenario
      @api.scenario(run['scenario_uuid'])

      # execute the test suite
      @api.run(run['testsuite_uuid'])

      if @api.collect_results == false
        $DEBUG and logger.debug "error returned from collect_results"
        stmt = "update runs set status='failed' where id='#{@run_id}'"
      else # add the test results to the database
          @api.results.each do | k, v |
           options = ""
           passed = ""
           test_id = ""
           message = ""
           name = k
           # results is a hashmap keyed by the test name
           # the value is another hashmap

           # get the test name from the hashmap
           #$DEBUG and logger.debug "test name = #{name}"

           # expand the inner hashmap, which contains 'options', 'passed' and 'id'
           v.each do | k2, v2 |
             if k2 == "options"

               # options are contained in yet another hashmap, keyed by 'options'
               v2.each do | k3, v3 |
                 options = options + "#{k3}=#{v3}:"  # string contains colon-separated key=value pairs
               end
               options = options[0, options.length-1] # lose the last colon
               #$DEBUG and logger.debug "  options = #{options}"
             else
               if k2 == "passed"
                 passed = v2
                # $DEBUG and logger.debug "  passed = #{passed}"
               end

               if k2 == "id"
                 test_id = v2
                 #$DEBUG and logger.debug test_id.to_i
                 #$DEBUG and logger.debug "  test_id = #{test_id}"
               end

               if k2 == "passed" and v2 == "false"
                  message = @api.failed[name]
                  #$DEBUG and logger.debug "  message = #{message}"
               end
             end # end if k2 == 'options'
           end # end v.each
           # for each result ... add it
           unless name == "END" or name == "END."
             created_at = Time.now.strftime("%Y-%m-%d %H:%M:%S")
             stmt = "INSERT INTO results (run_id, name, options, test_id, passed, message, created_at, updated_at)
                                values (#{@run_id}, '#{name}', '#{options}', #{test_id}, '#{passed}', '#{message}', '#{created_at}', '#{created_at}')"
             ActiveRecord::Base.connection.execute(stmt)
           end
        end   # end results.each
        stmt = "update runs set status='finished' where id='#{@run_id}'"
      end
      ActiveRecord::Base.connection.execute(stmt)
  #  end    # uncomment to use spawn
  end
  
end
